<?php

namespace App\Models;

use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class BaseModelold extends Model
{

    /**
     * Add module attributes for the model.
     * 
     * @return string
     */
    protected $module;

    /**
     * Add mslug attributes for the model.
     * 
     * @return string
     */
    protected $mslug;

    /**
     * Add defaultSort attributes for laravel-query-builder.
     * 
     * @return array
     */
    protected $sort;


    /**
     * Add allowedFilters attributes for laravel-query-builder.
     * 
     * @return array
     */
    protected $filters;


    /**
     * Add allowedFields attributes for laravel-query-builder.
     * 
     * @return array
     */
    protected $fields;


    /**
     * Add allowedIncludes attributes for laravel-query-builder.
     * 
     * @return array
     */
    protected $includes;


    //列表必须
    protected $listMust = [];    
    //列表隐藏，如内容等大字节字段
    protected $listHidden = [];
    //不允许检索
    protected $disableFilter=[];  

    //默认列表with$list_with
    protected $listWith = [];

    // 每页记录数，原值15
    protected $perPage = 10;

    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);
        if($this->module && empty($this->mslug)){
            $this->mslug = $mslug = $this->initMslug();
            static::addGlobalScope("avaiable", function (Builder $builder) use($mslug){
                $builder->where('mslug', $mslug);
            });
        }
    }

    //防错误追加 ??测试是否要求
    /*
    public function setMslugAttribute($value)
    {
        if ($this->mslug) {
            $value = $this->mslug;
        }
        $this->attributes['mslug'] = $value;
    }*/

    public function getQueryAll()
    {
        $result = [
            'module' => $this->getModule(),
            'mslug' => $this->getMslug(),
            'sort' => $this->getSort(),
            //'scopes'=> $this->getScopes(),
            'filters' => $this->getFilters(),
            'fields' => $this->getListFields(),
            'includes' => $this->getListwith(),
            'appends' => $this->getAppends(),
            'list_hidden' => $this->getListHidden(),
            'list_with' => $this->getListwith(),
            'list_fields' => $this->getListFields(),
        ];
        return $result;
    }

    public function getModule()
    {
        return $this->module;
    }

    protected function getMslug()
    {
        return $this->mslug;
    }


    /**
     * 默认排序字段
     */
    public function getSort()
    {
        if (empty($this->sort)) {
            $this->sort = $this->initSort();
        }
        return $this->sort;
    }

    public function setSort($sort = '')
    {
        return $this->sort = $sort;
    }



    /**
     * 允许过滤字段
     */
    public function getFilters()
    {
        if (is_null($this->filters)) {
            $this->filters = $this->initFilters();
        }
        return $this->filters;
    }

    public function setFilters($filters)
    {
        return $this->filters = $filters;
    }

    public function getAppends()
    {
        return $this->appends;
    }


    /**
     * 列表关联
     */
    public function getListWith()
    {
        return $this->listWith;
    }

    public function setListWith($list_with)
    {
        return $this->listWith = $list_with;
    }


    /**
     * 默认排序
     */
    protected function initSort()
    {
        if ($this->timestamps) {
            $sort = ['-created_at'];
        } elseif ($this->primaryKey) {
            $sort = ['-' . $this->primaryKey];
        } else {
            $sort = [];
        }
        return $sort;
    }

    protected function initSorts()
    {
        return [];
    }

    /**
     * 允许指定显示字段
     */
    protected function initFields()
    {
        //$fields = array_diff($this->displayFields(), $this->getListHidden());
        return $this->getListFields();
    }
    protected function initFilters()
    {
        return $this->getAllowedFilter();
    }

    /**
     * 模型标识
     * 返回 模块/模型
     */
    protected function initMslug()
    {
        return  $this->module.'/' . Str::slug(basename(str_replace('\\', '/', get_class($this))));
    } 
    
    
    /**
     * filters过滤
     */
    public function scopeFilters($query,$filters=null)
    {
        /*
        $wheres = [
            'where','or','bt','notbt','orbt','ornotbt','in','notin','orin','ornotin',
            'null','notnull','ornull','ornotnull','like','notlike','orlike','ornotlike',
            'date','year','month','day','time','col','orcol','tag','ortag',
			'orwhere','wherebt','wherenotbt','orwherebt','orwherenotbt','wherein','nowheretin','orwherein','orwherenotin',
            'wherenull','wherenotnull','orwherenull','orwherenotnull','wherelike','wherenotlike','orwherelike','orwherenotlike',
            'wheredate','whereyear','wheremonth','whereday','wheretime','wherecol','orwherecol','wheretag','orwheretag'
        ];   
        */    

        $act = ['select','hidden','sort','limit','offset'];

        if(is_null($filters)){
            $filters = request()->get('q');         //可config中设置   
        }        
        
        if(is_string($filters)){
            $filters = request()->get($filters);
        }
        if(!is_array($filters)){
            return $query;
        }
        $fields = $this->getAllowedFilter();

        $acts = array_intersect_key($filters,array_flip($act));
        $filters = array_intersect_key($filters,array_flip($fields));

        if(!empty($acts['select'])){
            $_fields = explode(',',$acts['select']);
            $listfields = $this->getListFields();
            $_fields = array_intersect($listfields,$_fields);
            if(count($_fields)){
                $query = $query->select($_fields);
            }
        }elseif(!empty($acts['hidden'])){
            $_fields = explode(',',$acts['hidden']);
            $listfields = $this->getListFields();                
            $_fields = array_diff($listfields,$_fields);
            if(count($_fields)){
                $query = $query->select($_fields);
            }
        }
   
        $query = $this->actFilter($query,$filters);

        return $query;

        //===
        if(!empty($acts['sort'])){
            $sorts = explode(',',$acts['sort']);
        }else{
            $sorts = $this->getSort();
        }
        
        if(!empty($sorts)){
            $fields = $this->getTableFields();
            foreach ($sorts as $k=>$s) {
                $_s = ltrim($s,'-');
                if(!in_array($_s,$fields)) continue;
                if($_s == $s){
                    $query = $query->orderBy($_s);
                }else{
                    $query = $query->orderBy($_s,'desc');
                }
            }
        }
        return $query;
    }

 

    
	public function getAllowedFilter()
	{
       $fields = $this->getTableFields();
       if($this->getDisableFilter()){
           $fields = array_diff($fields,$this->getDisableFilter());
       }
       return $fields;
    }


    /**
     * 查询禁止
     */

    public function setDisableFilter($disable_filter=[])
    {
        return $this->disableFilter = $disable_filter;
    }
    
    public function getDisableFilter()
    {
        return $this->disableFilter;
    }
    /**
     * 列表隐藏
     */

    public function setListHidden($list_hidden=[])
    {
        return $this->listHidden = $list_hidden;
    }

    public function getListHidden()
    {
        return $this->listHidden;
    }

    /**
     * 列必须
     */

    public function setListMust($list_must=[])
    {
        return $this->listMust = $list_must;
    }    
    public function getListMust()
    {
        return $this->listMust;
    }




    /**
     * 列表时默认显示字段
     * $listMust
     * $listFields
     * $listHidden
     */  
    public function getListFields()
    {
        $fields = $this->getVisibleFields();  //允许显示
        if ($this->listHidden) {
            //去掉列表隐藏
            $fields = array_diff($fields, $this->listHidden);
        } 
        if($this->listMust){   //列表必须,如id等
            //防列表必须中出现不存在的
            $must = array_intersect($fields,$this->listMust);
            //加入必须项
            $fields = array_merge($fields,$must);
        }
        return $fields;
    }


    /**
     * 模型所有可显示字段
     */
    public function getVisibleFields($model = false)
    {
        if($this->getVisible()){
            return array_merge($this->getVisible(),$this->getAppends());
        }else{            
            if($this->appends){
                $fields = array_merge($this->getTableFields(),$this->appends);
            }else{
                $fields = $this->getTableFields();
            }
            return array_diff($fields,$this->getHidden());
        }
        
    }
    /**
     * 模型表字段
     */
    protected function getTableFields($refrech=false){
        $table = $this->getTable();
        if($refrech || empty(\Cache::get('table-fields-'.$table))){	
            $fields = \Illuminate\Support\Facades\Schema::getColumnListing($table);			
			\Cache::forever('table-fields-'.$table,$fields);
        }else{
            $fields = \Cache::get('table-fields-'.$table);
        }        
        return $fields;
    }    

	protected function actFilter($query,$filters)
	{
        foreach ($filters as $field => $val) {        
            $param = explode(':',$val,3);
            if(empty($param)) continue;
           
            $where = $param[0];
            //dump($where);
            if(count($param)===1){
                switch ($where) {
                    case 'null':
                        $query = $query->whereNull($field);
                        break;                  
                    case 'ornull':
                        $query = $query->orWhereNull($field);
                        break;                    
                    case 'notnull':
                        $query = $query->whereNotNull($field);
                        break;                  
                    case 'ornotnull':
                        $query = $query->orWhereNotNull($field);
                        break;   
                    default:
                        $query = $query->where($field,$val);
                        break;                    
                } 
            }elseif(count($param)===2){
                if($where == '!>') $where = '<=';
                if($where == '!<') $where = '>=';
                switch ($where) {                    
                    case '<>':
                    case '<':
                    case '>':
                    case '<=':
                    case '>=':                      			
                        $query = $query->where($field,$where,$param[1]);
                        break;                      
                    case 'where':			
                        $query = $query->where($field,$param[1]);
                        break;                  
                    case 'or':
					case 'orwhere':
                        $query = $query->orWhere($field,$param[1]);
                        break;              
                    case 'like':    
                    case 'wherelike':
                        $query = $query->where($field,'like','%'.$param[1].'%');
                        break;    
                    case 'notlike':    
                    case 'wherenotlike':
                        $query = $query->where($field,'not like','%'.$param[1].'%');
                        break;    
                    case 'orlike':    
                    case 'orwherelike':
                        $query = $query->orWhere($field,'like','%'.$param[1].'%');
                        break;
                    case 'ornotlike':    
                    case 'orwherenotlike':
                        $query = $query->orWhere($field,'not like','%'.$param[1].'%');
                        break;      
                    case 'in':
                    case 'wherein':
                        $query = $query->whereIn($field,explode(',',$param[1]));
                        break;    
                    case 'notin':
					case 'wherenotin':
                        $query = $query->whereNotIn($field,explode(',',$param[1]));
                        break;    
                    case 'orin':
					case 'orwherein':
                        $query = $query->orWhereIn($field,explode(',',$param[1]));
                        break;
                    case 'ornotin':
					case 'orwherenotin':
                        $query = $query->orWhereNotIn($field,explode(',',$param[1]));
                        break;                        
                    case 'tag':    
                    case 'wheretag':
                        $query = $query->whereRaw('FIND_IN_SET(?,'.$field.')',explode(',',$param[1]));
                        break;
                    case 'ortag':    
                    case 'orwheretag':
                        $query = $query->orWhereRaw('FIND_IN_SET(?,'.$field.')',explode(',',$param[1]));
                        break;                        
                    case 'bt':
					case 'wherebetween':
						$query = $query->whereBetween($field,explode(',',$param[1],2));
                        break;                  
                    case 'orbt':
					case 'orwherebetween':
						$query = $query->orWhereBetween($field,explode(',',$param[1],2));
                        break;                    
                    case 'notbt':
					case 'wherenotbetween':
						$query = $query->whereNotBetween($field,explode(',',$param[1],2));
                        break;                  
                    case 'ornotbt':
					case 'orwherenotbetween':
						$query = $query->orWhereNotBetween($field,explode(',',$param[1],2));
                        break;                         
                    case 'date':
					case 'wheredate':
						if(strtotime($param[1])){
							$query = $query->whereDate($field,$param[1]);
						}
                        break;                  
                    case 'year':
					case 'whereyear':
						if(is_numeric($param[1])){
							$query = $query->WhereYear($field,$param[1]);
						}
                        break;                    
                    case 'month':
					case 'wheremonth':
						if(is_numeric($param[1])){
	                        $query = $query->whereMonth($field,$param[1]);
						}
                        break;                  
                    case 'day':
                    case 'whereday':
						if(is_numeric($param[1])){
							$query = $query->WhereDay($field,$param[1]);
						}
                        break;                                  
                    case 'time':
					case 'wheretime':
						if(strtotime($param[1])){
							$query = $query->whereTime($field,$param[1]);
						}
                        break;   
                    case 'col':
					case 'wherecolumn':
                        if(in_array($param[1],array_merge($this->getTableFields(),$this->appends))){
                            $query = $query->whereColumn($field,$param[1]);
                        }
                        break;                                  
                    case 'orcol':
					case 'orwherecolumn':
                        if(in_array($param[1],array_merge($this->getTableFields(),$this->appends))){
                            $query = $query->orWhereColumn($field,$param[1]);
                        }
                        break;   
                    default:
                        $query = $query->where($field,$val);
                        break;                                         
                }    
            }elseif(in_array($param[1],['>','<','<>','!>','!<'])){   
                if($param[1] == '!>') $param[1] = '<=';
                if($param[1] == '!<') $param[1] = '>=';                
                switch ($where) {
                    case 'where':			
                        $query = $query->where($field,$param[1],$param[2]);
                        break;                  
                    case 'or':
					case 'orwhere':
                        $query = $query->orWhere($field,$param[1],$param[2]);
                        break;              
                    case 'date':
                    case 'wheredate':
						if(strtotime($param[2])){
							$query = $query->whereDate($field,$param[1],$param[2]);
						}
                        break;                  
                    case 'year':
					case 'whereyear':
						if(is_numeric($param[2])){
							$query = $query->WhereYear($field,$param[1],$param[2]);
						}
                        break;                    
                    case 'month':
					case 'wheremonth':
						if(is_numeric($param[2])){
                            $query = $query->whereMonth($field,$param[1],$param[2]);
                        }
                        break;                  
                    case 'day':
					case 'whereday':
						if(is_numeric($param[2])){
	                        $query = $query->WhereDay($field,$param[1],$param[2]);
						}
                        break;                                  
                    case 'time':
					case 'wheretime':
						if(strtotime($param[2])){
							$query = $query->whereTime($field,$param[1],$param[2]);
						}
                        break;  
                    case 'col':
					case 'wherecolumn':
                        if(in_array($param[2],array_merge($this->getTableFields(),$this->appends))){
                            $query = $query->whereColumn($field,$param[1],$param[2]);
                        }
                        break;                                  
                    case 'orcol':
					case 'orwherecolumn':				
                        if(in_array($param[1],array_merge($this->getTableFields(),$this->appends))){
                            $query = $query->orWhereColumn($field,$param[1],$param[2]);
                        }
                        break;                                                       
                }                  
            }
        }	   
	}

}



/**
 * 参考 model初始设置
 * protected:
 *  $connection, $table,$primaryKey = 'id',$keyType = 'int',$with = [],$withCount = [],$perPage = 15,
 *  $attributes = [],$original = [],$changes = [], $casts = [],$dates = [],$dateFormat(string),$appends = [],
 *  $relations = [],$touches = []联动更新关系,
 *  $fillable = [],$guarded = ['*'],
 *  $hidden = [],$visible = [],
 *  $dispatchesEvents = [],$observables = [],
 * 
 * public
 *  $exists = false,$wasRecentlyCreated = false,$incrementing = true,
 *  $snakeAttributes = true,$timestamps = true,
 * 
 * protected static
 *  $resolver,$dispatcher,$booted = [],$traitInitializers = [],
 *  $globalScopes = [],$ignoreOnTouch = [],$mutatorCache = [],
 *  $unguarded = false,
 * 
 * const
 *  CREATED_AT = 'created_at',UPDATED_AT = 'updated_at',   
 */
